function result = rdd_format(rawData,rawW,varnames)

    % idpair = {'gvkey1','gvkey2'};
    % tvar = 'fyear';
    % idvar = 'gvkey';
    % yvar = 'inv_lead';
    % xvars = {'ln_sale','roa','bl','mb'};

    % extract variable names
    idpair  = varnames.idpair;
    tvar    = varnames.tvar;
    idvar   = varnames.idvar;
    yvar    = varnames.yvar;
    xvars   = varnames.xvars;


    % merge (join) tables to ensure W matches data
    ids = unique(rawW(:,[idpair(1),tvar]), 'rows');
    ids.Properties.VariableNames{idpair(1)} = idvar;
    ids = sortrows(ids,{tvar,idvar});

    ModData = sortrows(innerjoin(rawData, ids),{tvar,idvar});

    % eliminate missing values
    TF = (sum(isnan(ModData{:,[yvar, xvars]}), 2) == 0);
    ModData = ModData(TF,:);

    rawW = rawW(:,[idpair,tvar,'score']);

    % keep IDs and generate a new index for IDs
    ids = sortrows(ModData(:,idvar));
    ids = [ids array2table((1:size(ids,1))')];
    ids.Properties.VariableNames = {idvar,'altid'};

    % Create annual W matrix
    rawW1 = innerjoin(rawW,ids,'LeftKey',1,'RightKey',1);
    rawW1.Properties.VariableNames{'altid'} = 'altid1';

    rawW2 = innerjoin(rawW1,ids,'LeftKey',2,'RightKey',1);
    rawW2.Properties.VariableNames{'altid'} = 'altid2';

    % make sure the matrix is symmetric (some firms might drop)
    iota = ones(size(ids,1),1);
    tmp = array2table([ids{:,'gvkey'}, ids{:,'gvkey'}, iota, 0*iota,...,
                       ids{:,'altid'}, ids{:,'altid'}]);
    tmp.Properties.VariableNames = rawW2.Properties.VariableNames;
    rawW2 = [rawW2; tmp];

    SCORE = rawW2{:,'score'};
    FIRM1 = rawW2{:,'altid1'};
    FIRM2 = rawW2{:,'altid2'};

    W = normw(sparse(FIRM1, FIRM2, SCORE));

    result.data = ModData;
    result.w = W;